﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
using System.Xml;

namespace ORMDemo.Dal.ExpressionExtend
{
    public class CustomExpressionVisitor : ExpressionVisitor
    {
        private Stack<string> ConditionStack = new Stack<string>();
        public string GetWhere()
        {
            string where = string.Concat(ConditionStack.ToArray());
            ConditionStack.Clear();
            return where;
        }
        public override Expression Visit(Expression node)
        {
            Console.WriteLine($"Visit:{node.NodeType}{node.Type}{node.ToString()}");
            return base.Visit(node);
        }
        protected override Expression VisitBinary(BinaryExpression node)
        {
            Console.WriteLine($"VisitBinary:{node.NodeType}{node.Type}{node.ToString()}");
            ConditionStack.Push(" ) ");
            base.Visit(node.Right);
            ConditionStack.Push(node.NodeType.ToSqlOperator());
            base.Visit(node.Left);
            ConditionStack.Push(" ( ");

            return node;
        }
        protected override Expression VisitConstant(ConstantExpression node)
        {
            Console.WriteLine($"VisitConstant:{node.NodeType}{node.Type}{node.ToString()}");
            ConditionStack.Push($"'{node.Value.ToString()}'");
            return base.VisitConstant(node);
        }
        protected override Expression VisitMember(MemberExpression node)
        {
            Console.WriteLine($"VisitMember:{node.NodeType}{node.Type}{node.ToString()}");
            ConditionStack.Push($"'{node.Member.Name}'");
            return base.VisitMember(node);
        }
        protected override Expression VisitMethodCall(MethodCallExpression m)
        {
            if (m == null) throw new ArgumentNullException("MethodCallExpression");
            string format;
            switch (m.Method.Name)
            {
                case "StartsWith":
                    format = "({0} like {1}+'%')";
                    break;
                case "Contains":
                    format = "({0} like '%'+{1}+'%')";
                    break;
                case "EndsWith":
                    format = "({0} like '%'+{1})";
                    break;
                    default:
                    throw new NotSupportedException(m.NodeType + " is not supported");
            }
            Visit(m.Object);
            Visit(m.Arguments[0]);
            string right=ConditionStack.Pop();
            string left = ConditionStack.Pop();
            ConditionStack.Push(String.Format(format, left, right));
            return m;
        }
    }
}
